package com.netty;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netty.common.MyInitializer;
import com.netty.common.Result;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.*;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.SocketUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import static io.netty.buffer.Unpooled.copiedBuffer;

/**
 * netty http 客户端
 *
 * @author gjj
 */
public class HttpClient {


    public Bootstrap b = new Bootstrap();

    public HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);

    public ObjectMapper objectMapper = new ObjectMapper();

    private EventLoopGroup group = new NioEventLoopGroup();


    public HttpClient() {
        try {
            b.group(group).channel(NioSocketChannel.class)
                    .handler(new MyInitializer(new HttpClientHandler(), true, true));
        } catch (Exception e) {
            e.printStackTrace();
            group.shutdownGracefully();
            factory.cleanAllHttpData();
        }
    }

    /**
     * 发送get请求
     **/
    public Object doGet(String url, HashMap params) {
        try {
            //链接uri
            URI uriSimple = new URI(url);
            //主机地址
            String host = uriSimple.getHost();
            //端口
            Integer port = uriSimple.getPort();
            //建立频道
            Channel channel = b.connect(host, port).sync().channel();
            //设置请求参数
            QueryStringEncoder encoder = new QueryStringEncoder(url);
            Iterator<Map.Entry> iterator = params.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry next = iterator.next();
                encoder.addParam(next.getKey().toString(), next.getValue().toString());
            }

            //设置请求头
            URI uriGet = new URI(encoder.toString());
            HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
            setHeaders(request, host, uriSimple);

            //调用连接
            Object object = HttpClientHandler.call(request, null, channel,false,null);
            String json = (String) object;
            return json;
        } catch (Exception e) {
            e.printStackTrace();
            group.shutdownGracefully();
            factory.cleanAllHttpData();
            return errorResult(e);
        }
    }

    private String errorResult(Exception e){
        try {
            return objectMapper.writeValueAsString(Result.errorResult(e.getMessage()));
        } catch (JsonProcessingException e1) {
            return null;
        }
    }
    /**
     * 表单请求
     */
    public String doPost(String url, HashMap params,boolean isFile,String filePath) {
        try {
            //链接uri
            URI uriSimple = new URI(url);
            //主机地址
            String host = uriSimple.getHost();
            //端口
            Integer port = uriSimple.getPort();
            //建立频道
            Channel channel = b.connect(host, port).sync().channel();

            HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());

            //body请求参数
            HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false);

            //设置请求头
            HttpHeaders headers = request.headers();
            setHeaders(request, host, uriSimple);
            headers.set(HttpHeaderNames.CONTENT_TYPE, "application/x-www-form-urlencoded");
            Iterator<Map.Entry> iterator = params.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry next = iterator.next();
                bodyRequestEncoder.addBodyAttribute(next.getKey().toString(), next.getValue().toString());
            }

            // 把body放到request
            request = bodyRequestEncoder.finalizeRequest();

            //调用请求
            String json = (String) HttpClientHandler.call(request, null, channel,isFile,filePath);

            return json;

        } catch (Exception e) {
            e.printStackTrace();
            group.shutdownGracefully();
            factory.cleanAllHttpData();
            return errorResult(e);
        }
    }


    /**
     * 发送json
     */
    public String doPostJson(String url, String json) {
        try {
            //链接uri
            URI uriSimple = new URI(url);
            //主机地址
            String host = uriSimple.getHost();
            //端口
            Integer port = uriSimple.getPort();
            //建立频道
            Channel channel = b.connect(host, port).sync().channel();
            //把json转为netty的bytebuf
            ByteBuf buf = copiedBuffer(json, CharsetUtil.UTF_8);
            //获取fuulhttprequest (请求头、请求body)
            DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1,
                    HttpMethod.POST, uriSimple.toASCIIString());
            //请求body写入bytebuf
            request.content().writeBytes(buf);
            //设置请求头
            HttpHeaders headers = request.headers();
            setHeaders(request, host, uriSimple);
            //设置content-type为json请求
            headers.set(HttpHeaderNames.CONTENT_TYPE, "application/json");
            //需要手动指定body长度
            headers.setInt(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes());


            //调用请求
            String resultjson = (String) HttpClientHandler.call(request, null, channel,false,null);


            return resultjson;


        } catch (Exception e) {
            e.printStackTrace();
            group.shutdownGracefully();
            factory.cleanAllHttpData();
            return errorResult(e);
        }
    }


    /**
     * multipart  form-data 文件上传
     */
    public String doPostMultipart(String url, HashMap params, HashMap headers) {
        try {
            //链接uri
            URI uriSimple = new URI(url);
            //主机地址
            String host = uriSimple.getHost();
            //端口
            Integer port = uriSimple.getPort();
            //建立频道
            Channel channel = b.connect(SocketUtils.socketAddress(host, port)).sync().channel();
            //request请求 (请求行、请求头)
            HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
                    HttpMethod.POST, uriSimple.toASCIIString());


            //设置头部
            Iterator<Map.Entry> headeriterator = headers.entrySet().iterator();
            while (headeriterator.hasNext()) {
                Map.Entry next = headeriterator.next();
                request.headers().set(next.getKey().toString(), next.getValue());
            }
            setHeaders(request, host, uriSimple);
            //添加额外表单属性
            //请求body编码器
            HttpPostRequestEncoder bodyRequestEncoder =
                    new HttpPostRequestEncoder(factory, request, true);

            Iterator<Map.Entry> iterator = params.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry next = iterator.next();
                if (next.getValue() instanceof File) {
                    bodyRequestEncoder.addBodyFileUpload(next.getKey().toString(), (File) next.getValue(), "application/x-zip-compressed", false);
                } else {
                    bodyRequestEncoder.addBodyAttribute(next.getKey().toString(), next.getValue().toString());
                }
            }

            //把最终的bodyRequestEncoder 放入到request中
            bodyRequestEncoder.finalizeRequest();


            String call = (String) HttpClientHandler.call(request, bodyRequestEncoder, channel,false,null);

            //清空传输缓存中的文件
            bodyRequestEncoder.cleanFiles();


            return call;

        } catch (Exception e) {
            e.printStackTrace();
            group.shutdownGracefully();
            factory.cleanAllHttpData();
            return errorResult(e);
        }
    }


    public void close() {
        group.shutdownGracefully();
        factory.cleanAllHttpData();
    }


    private void setHeaders(HttpRequest request, String host, URI uriSimple) {
        HttpHeaders headers = request.headers();
        headers.set(HttpHeaderNames.HOST, host);
        headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
        headers.set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP + "," + HttpHeaderValues.DEFLATE);
        headers.set(HttpHeaderNames.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
        headers.set(HttpHeaderNames.ACCEPT_LANGUAGE, "fr");
        headers.set(HttpHeaderNames.REFERER, uriSimple.toString());
        headers.set(HttpHeaderNames.USER_AGENT, "Netty Simple Http Client side");
        headers.set(HttpHeaderNames.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    }


}
